home *** CD-ROM | disk | FTP | other *** search
/ SGI Hot Mix 17 / Hot Mix 17.iso / HM17_SGI / research / examples / demo / demosrc / d_reconstr.pro < prev    next >
Text File  |  1997-07-08  |  45KB  |  1,364 lines

  1. ;$Id: d_reconstr.pro,v 1.25 1997/04/18 23:01:28 tremblay Exp $
  2. ;
  3. ;  Copyright (c) 1997, Research Systems, Inc. All rights reserved.
  4. ;       Unauthorized reproduction prohibited.
  5. ;
  6. ;+
  7. ;  FILE:
  8. ;       d_reconstr.pro
  9. ;
  10. ;  CALLING SEQUENCE: d_reconstr
  11. ;
  12. ;  PURPOSE:
  13. ;       Shows reconstruction techniques for images.
  14. ;       (Computerized tomography)
  15. ;
  16. ;  MAJOR TOPICS: Visualization and data analysis
  17. ;
  18. ;  CATEGORY:
  19. ;       IDL 5.0
  20. ;
  21. ;  INTERNAL FUNCTIONS and PROCEDURES:
  22. ;       pro DemoMenuChoice      -  Identify the menu button choice
  23. ;       pro DemoMenuCreate      -  Create the menu bar
  24. ;       pro None                -  Set the filter to none
  25. ;       pro Ramlak              -  Compute the Ramlak filter
  26. ;       pro Shepp_Logan         -  Compute the Shepp_Logan filter
  27. ;       pro Lp_Cosine           -  Compute the Lp_Cosine filter
  28. ;       pro Gen_Hamming         -  Compute the Gen_Hamming filter
  29. ;       pro DEllipse            -  Draw an ellipse
  30. ;       pro DCircle             -  Draw a circle
  31. ;       pro DPoly               -  Draw a polygon
  32. ;       pro Make_Phantom        -  Create a phantom object
  33. ;       pro Reconstruct_It      -  Do the image reconstruction
  34. ;       pro Recon_Redraw        -  Redraw the windows
  35. ;       pro Rec_Demo_Event      -  Event handler
  36. ;       pro Reconstr_Cleanup    -  Cleanup
  37. ;       pro D_Reconstr            -  Main procedure
  38. ;
  39. ;  EXTERNAL FUNCTIONS, PROCEDURES, and FILES:
  40. ;       pro gettips             -  Read the tip file
  41. ;       pro widtips             -  Create the tip widgets
  42. ;       pro sizetips            -  Size the tip widgets
  43. ;       pro sizetips            -  Change the tips text
  44. ;       reconstr.txt
  45. ;       reconstr.tip
  46. ;       ctscan.dat
  47. ;
  48. ;  REFERENCE: IDL Reference Guide, IDL User's Guide
  49. ;
  50. ;  NAMED STRUCTURES:
  51. ;       none.
  52. ;
  53. ;  COMMON BLOCS:
  54. ;       tomodemo_com
  55. ;
  56. ;  MODIFICATION HISTORY:
  57. ;       1/94,   DS   - Written.
  58. ;       1/97,   DAT  - New GUI, IDL Style Guide.
  59. ;-
  60. ;--------------------------------------------------------------------
  61. ;
  62. ;    PURPOSE  Given a uservalue from a menu button created
  63. ;             by MenuCreate, the function returns  the index 
  64. ;             of the choice within the category.  Set the
  65. ;             selected menu button  to insensitive to signify
  66. ;             selection, and set all other choices for the
  67. ;             category to sensitive.
  68.  
  69. function DemoMenuChoice, $
  70.     Eventval, $   ; IN: uservalue from seleted menu button
  71.     MenuItems, $  ; IN: menu item array, as returned by MenuCreate
  72.     MenuButtons   ; IN: button array as returned by MenuCreate
  73.  
  74.     ;  Get the name less the last qualifier.
  75.     ;
  76.     i = STRPOS(eventval, '|', 0) 
  77.     while (i ge 0) do begin
  78.         j = i 
  79.         i = STRPOS(eventval, '|', i+1) 
  80.     endwhile
  81.  
  82.     base = STRMID(eventval, 0, j+1) ;common buttons, includes last |
  83.  
  84.     ;  Get the button sharing this basename.
  85.     ;
  86.     buttons = WHERE(STRPOS(MenuItems, base) eq 0)
  87.  
  88.     ;  Get the index of selected item.
  89.     ;
  90.     this = (WHERE(eventval eq MenuItems))(0)
  91.  
  92.     ;  For each button in category, sensitize.
  93.     ;
  94.     for i=0, N_ELEMENTS(buttons)-1 do begin 
  95.         index = buttons(i)
  96.         WIDGET_CONTROL, MenuButtons(buttons(i)), SENSITIVE=index ne this
  97.     endfor
  98.  
  99.     ;  Return the Selected button's index.
  100.     ;
  101.     RETURN, this - buttons(0)
  102.  
  103. end
  104.  
  105. ;--------------------------------------------------------------------
  106. ;
  107. ;    PURPOSE  Create a menu from a string descriptor (MenuItems).
  108. ;             Return the parsed menu items in MenuItems (overwritten),
  109. ;             and the array of corresponding menu buttons in MenuButtons.
  110. ;
  111. ;  MenuItems = (input/output), on input the menu structure in the form of
  112. ;          a string array.  Each button is an element, encoded as follows:
  113. ;  Character 1 = integer bit flag.  Bit 0 = 1 to denote a button with
  114. ;        children.  Bit 1 = 2 to denote this is the last child of its
  115. ;        parent.  Bit 2 = 4 to show that this button should initially
  116. ;        be insensitive, to denote selection.  Any combination of bits
  117. ;        may be set.
  118. ;        On RETURN, MenuItems contains the fully qualified button names.
  119. ; Characters 2-end = Menu button text.  Text should NOT contain the character
  120. ;        |, which is used to delimit menu names.
  121. ; MenuButtons = (output) button widget id's of the created menu.
  122. ; Bar_base = (input) ID of menu base.
  123. ; Prefix = prefix for this menu's button names.  If omitted, no
  124. ;     prefix.
  125. ;
  126. ;
  127. ; Example:
  128. ;  MenuItems = ['1File', '0Save', '2Exit', $
  129. ;        '1Edit', '3Cut', $
  130. ;        '3Help']
  131. ;  Creates a menu with three top level buttons (file, edit and help).
  132. ;  File has 2 choices (save and exit), Edit has one choice, and help has none.
  133. ;  On RETURN, MenuItems contains the fully qualified menu button names
  134. ;  in a string array of the form: ['<Prefix>|File', '<Prefix>|File|Save', 
  135. ;    '<Prefix>|File|Exit', '<Prefix>|Edit',..., etc. ]
  136. ;
  137. pro DemoMenuCreate, $
  138.     MenuItems, $    ; IN/OUT: menu structure/button names 
  139.     MenuButtons, $  ; OUT: button widget identifier
  140.     Bar_base,  $    ; IN: menu bar base identifier
  141.     Prefix=prefix   ; IN: (opt) prefix of the menu's button names
  142.  
  143.     ;  Initialize working variables and arrays.
  144.     ;
  145.     level = 0
  146.     parent = [bar_base, 0, 0, 0, 0, 0]
  147.     names = STRARR(5)
  148.     lflags = INTARR(5)
  149.     MenuButtons = LONARR(N_ELEMENTS(MenuItems))
  150.  
  151.     if (N_ELEMENTS(prefix)) then begin
  152.         names(0) = prefix + '|'
  153.     endif else begin
  154.         names(0) = '|'
  155.     endelse
  156.  
  157.     for i = 0, N_ELEMENTS(MenuItems)-1 do begin
  158.         flag = FIX(STRMID(MenuItems(i), 0, 1))
  159.     txt = STRMID(MenuItems(i), 1, 100)
  160.     uv = ''
  161.  
  162.     for j = 0, level do uv = uv + names(j)
  163.  
  164.         ;  Set the fully qualified name in the menuItems array.
  165.         ;
  166.         MenuItems(i) = uv + txt  
  167.  
  168.         ;  Create the menu bar buttons.
  169.         ;
  170.         MenuButtons(i) = WIDGET_BUTTON(parent(level), $
  171.             VALUE=txt, UVALUE=uv+txt, $
  172.             MENU=flag and 1, HELP=txt eq 'About')
  173.  
  174.         if ((flag and 4) ne 0) then begin
  175.             WIDGET_CONTROL, MenuButtons(i), SENSITIVE=0
  176.         endif
  177.  
  178.         if (flag and 1) then begin
  179.             level = level + 1
  180.             parent(level) = MenuButtons(i)
  181.             names(level) = txt + '|'
  182.             lflags(level) = (flag AND 2) ne 0
  183.         endif else if ((flag and 2) NE 0) then begin
  184.  
  185.             ;  Pop the previous levels.
  186.             ;
  187.             while (lflags(level)) do level = level-1
  188.  
  189.             ;  Pop this level.
  190.             ;
  191.             level = level - 1   
  192.         endif
  193.     endfor
  194.  
  195. end         ;  of DemoMenuCreate
  196.  
  197.  
  198. ;--------------------------------------------------------------------
  199. ;
  200. ;    PURPOSE  Create the reconstruction filter : none
  201. ;
  202. function None, $
  203.     x, $           ; IN: x coordinates
  204.     pointSpacing   ; IN: point spacing
  205.  
  206.     RETURN, [1.0]
  207. end      ;   of None
  208.  
  209. ;--------------------------------------------------------------------
  210. ;
  211. ;    PURPOSE  Create the reconstruction filter : RAMLAK
  212. ;
  213. function Ramlak, $
  214.     x, $           ; IN: x coordinates
  215.     pointSpacing   ; IN: point spacing
  216.  
  217.     zero = where(x EQ 0.0, count)
  218.     q = x
  219.     if (count NE 0) then q(zero) = .01
  220.     y = -SIN(!pi*x/2)^2 / (!pi^2 * q^2 * pointSpacing)
  221.     if (count NE 0) then y(zero) = 1./(4.*pointSpacing)
  222.     RETURN, y
  223. end
  224.  
  225. ;--------------------------------------------------------------------
  226. ;
  227. ;    PURPOSE  Create the reconstruction filter : Shepp_Logan
  228. ;
  229. function Shepp_Logan,$
  230.     x, $           ; IN: x coordinates
  231.     pointSpacing   ; IN: point spacing
  232.  
  233.     pointSpacing = !pi^2 * pointSpacing * (1.-4.*x^2)
  234.     zeros = where(abs(pointSpacing) LE 1.0e-6, count)
  235.     if (count ne 0) then pointSpacing(zeros) = .001
  236.     RETURN, 2./pointSpacing
  237. end
  238.  
  239. ;--------------------------------------------------------------------
  240. ;
  241. ;    PURPOSE  Create the reconstruction filter : Lp_Cosine
  242. ;
  243. function Lp_Cosine, $
  244.     x, $           ; IN: x coordinates
  245.     pointSpacing   ; IN: point spacing
  246.  
  247.     RETURN, 0.5 * (ramlak(x-.5, pointSpacing) + $
  248.         ramlak(x+.5, pointSpacing))
  249. end
  250.  
  251. ;--------------------------------------------------------------------
  252. ;
  253. ;    PURPOSE  Create the reconstruction filter : Gen_Hamming
  254. ;
  255. function Gen_Hamming, $
  256.     x, $              ; IN: x coordinates
  257.     pointSpacing, $   ; IN: point spacing
  258.     alpha             ; IN: alpha attenuation factor
  259.  
  260.     if (N_ELEMENTS(alpha) LE 0) then alpha = 0.5
  261.     RETURN, alpha * ramlak(x, pointSpacing) + ((1.-alpha)/2) * $
  262.         (ramlak(x-1, pointSpacing) + ramlak(x+1, pointSpacing))
  263. end
  264.  
  265.  
  266. ;--------------------------------------------------------------------
  267. ;
  268. ;    PURPOSE  Fill an elliptical area within an array with a given value.
  269. ;
  270. pro DEllipse, $
  271.     regionArray, $      ; IN/OUT: array
  272.     x0, $               ; IN: x loaction of the ellipse center
  273.     y0, $               ; IN: y loaction of the ellipse center
  274.     rx, $               ; IN: radius in x of the ellipse
  275.     ry, $               ; IN: radius in y of the ellipse
  276.     theta, $            ; IN: angle of the major axis
  277.     value               ; IN: value given to a point within the ellipse.
  278.  
  279.     s = SIZE(regionArray)
  280.     nx = s(1)
  281.     ny = s(2)
  282.     n = 64          ;# of points around ellipse
  283.     x = FINDGEN(n) * (2 * !pi / n)
  284.     y = ry * SIN(x)
  285.     x = rx * COS(x)
  286.     t = theta * !dtor
  287.     yp = (COS(t) * y + SIN(t) * x + y0) * (ny/2) + (ny/2)
  288.     x = (COS(t) * x - SIN(t) * y + x0) * (nx/2) + (nx/2)
  289.     regionArray(POLYFILLV(x, yp, nx, ny)) = value
  290. end
  291.  
  292. ;--------------------------------------------------------------------
  293. ;
  294. ;    PURPOSE  Fill a circular area within an array with a given value.
  295. ;
  296. pro DCircle, $
  297.     regionArray, $      ; IN/OUT: array
  298.     r, $                ; IN: radius of the circle
  299.     x0, $               ; IN: x location of the circle center
  300.     y0, $               ; IN: y location of the circle center
  301.     value               ; IN; value 
  302.  
  303.     s = SIZE(regionArray)
  304.     n = 100
  305.     x = FINDGEN(n) * (2 * !pi / n)
  306.     y = r * SIN(x) + y0
  307.     x = r * COS(x) + x0
  308.     regionArray(POLYFILLV(x, y, s(1), s(2))) = value
  309. end
  310.  
  311. ;--------------------------------------------------------------------
  312. ;
  313. ;    PURPOSE Draw a polygon within an array
  314. ;
  315. pro DPoly, $
  316.     regionArray, $      ; IN/OUT: array
  317.     x, $                ; IN: x location of the polygon center
  318.     y, $                ; IN: y location of the polygon center
  319.     value               ; IN: value
  320.  
  321.     s =size(regionArray)
  322.     regionArray(POLYFILLV(x, y, s(1), s(2))) = value
  323. end
  324.  
  325. ;--------------------------------------------------------------------
  326. ;
  327. ;    PURPOSE  Create the phantom (image) objects.
  328. ;
  329. function Make_Phantom, $
  330.     imageSize, $     ; IN: Image size
  331.     object           ; IN: Object identifier, see list below
  332.  
  333.     case object of
  334.  
  335.         ;  Create squares.
  336.         ;
  337.         0: Begin
  338.             rslt = FLTARR(imageSize, imageSize)
  339.             rslt(imageSize/2, imageSize/2) = 1.0
  340.         endcase
  341.  
  342.         ;  Create ellipses.
  343.         ;
  344.         1:  begin     
  345.             rslt = FLTARR(imageSize, imageSize)
  346.             dellipse, rslt,    0,     0,   .69,   .92,    0,  1.0 ;a
  347.             dellipse, rslt,    0,-.0184, .6624, .8740,    0,  0.34 ;b
  348.             dellipse, rslt,  .22,    0.,   .11,   .31,  -18,  0. ;c
  349.             dellipse, rslt, -.22,    0.,   .16,   .41,   18,  0. ;d
  350.             dellipse, rslt,   0.,   .35,   .21,   .25,   0.,  0.67 ;e
  351.             dellipse, rslt,   0.,   .35,   .05,   .05,   0.,  0.57 ;Extra
  352.             dellipse, rslt,   0.,    .1,  .046,  .046,   0.,   .67 ;f
  353.             dellipse, rslt,   0.,   -.1,  .046,  .046,   0.,   .67 ;g
  354.             dellipse, rslt, -.08, -.605,  .046,  .023,   0.,   .67 ;h
  355.             dellipse, rslt,   0., -.606,  .023,  .023,   0.,   .67 ;i
  356.             dellipse, rslt, 0.06, -.605,  .023,  .046,   0.,   .67 ;j
  357.             dellipse, rslt, -.49, -.470,  .050,  .050,   0.,  1.00 ;j
  358.         endcase
  359.  
  360.         ;  Create circles.
  361.         ;
  362.         2: begin         
  363.             rslt = FLTARR(imageSize, imageSize)
  364.             dcircle, rslt, imageSize/4,  .5*imageSize,  .5*imageSize, .5
  365.             dcircle, rslt, imageSize/12, .6*imageSize,  .6*imageSize, 0.0
  366.             dcircle, rslt, imageSize/12, .38*imageSize, .37*imageSize, 1.
  367.             dcircle, rslt, imageSize/12, .7*imageSize,  .2*imageSize, 1.
  368.             dcircle, rslt, 3, .28*imageSize, .60*imageSize, 0.0
  369.             dpoly, rslt, imageSize*[.55, .60, .65], imageSize * [.37, .45, .37], 0
  370.             rslt(imageSize*[.117, .195], imageSize*[.781, .855]) = .5
  371.         endcase
  372.  
  373.         ;  Create polygons.
  374.         ;
  375.         3: begin
  376.             rslt = FLTARR(imageSize, imageSize)
  377.             x = imageSize/3
  378.             y = 2 * imageSize / 3
  379.             s = 2
  380.             rslt(x-s:x+s, y-s:y+s) = 1.0
  381.             rslt(y,x)=1.0
  382.             s = 4
  383.             rslt(x-s:x+s, x-s:x+s) = 0.5
  384.             dpoly, rslt, [y-s, y+s, y], [y-s, y-s, y+s], 1.0
  385.         endcase
  386.  
  387.         ;  Download the CT scan image (slice), resize, and scale it.
  388.         ;
  389.         4: begin 
  390.             OPENR,unit, filepath('ctscan.dat', $
  391.                 SUBDIR=['examples','data']), $
  392.                 /GET_LUN
  393.             imageArray=BYTARR(256,256)
  394.             READU, unit, imageArray
  395.             CLOSE, unit
  396.             FREE_LUN, unit
  397.             imageArray = (imageArray < 200b)/ 200.    ;Normalize
  398.             if (imageSize LT 256) then rslt = CONGRID(imageArray, $
  399.                 imageSize, imageSize, /INTERP) $
  400.             else if (imageSize GT 256) then begin
  401.                 rslt = FLTARR(imageSize, imageSize)
  402.                 rslt((imageSize-256)/2, (imageSize-256)/2) = imageArray ;Insert
  403.             endif else rslt = imageArray     ;already correct size.
  404.         endcase
  405.     endcase
  406.  
  407.     RETURN, rslt
  408.  
  409. end       ;  of Make_Phantom
  410.  
  411. ;--------------------------------------------------------------------
  412. ;
  413. ;    PURPOSE   Reconstruct (recompute) the image and display it.
  414. ;
  415. pro Reconstruct_It             
  416.  
  417.     COMMON tomodemo_com, base, imageSize, $
  418.         interp, nangles, kernelSize, filter, $
  419.         draw, window, labels, lnames, top, shiftValue, pointSpacing, $
  420.         filters, obj_button, object, zoomFactor, maxa, mina, ocolors, $
  421.         MenuItems, MenuButtons, wReconstructButton, wAngleButton, wFilterButton, $
  422.         wKernelButton, wInterpButton, drawErrorID, errorBase, $
  423.         Bar_Base, wSubBase, $ ; base ID to desensitize when computing.
  424.         ReconstructFlag, $            ; 0 = Go button has not  been pushed yet
  425.         originalImage, reconImage, sinogramImage, $          ; Images
  426.         sText, wText, $      ; widget ids and text structure for tips.
  427.         pimage, pimagestr, nimages, comp_view ;history
  428.  
  429.     ;  Desensitize the bases during reconstruction.
  430.     ;
  431.     WIDGET_CONTROL, Bar_base, SENSITIVE=0
  432.     WIDGET_CONTROL, wSubBase, SENSITIVE=0
  433.  
  434.     ;  Initialize the windows labels (names).
  435.     ;
  436.     lnames2 = ['Original (Click window)', $
  437.               'Reconstruction          ', $
  438.               'Sinogram (Click window) ', $
  439.               'Error (Click window)    ']
  440.     ;  Create the widgets starttin g with the top level base.
  441.     for i=0,3 do begin
  442. ;        WIDGET_CONTROL, labels(i), SET_VALUE=lnames(i)
  443.         WIDGET_CONTROL, labels(i), SET_VALUE=lnames2(i)
  444.     endfor
  445.  
  446.     ;  Redraw the original image by showing the angle line.
  447.     ;
  448.     WSET, window(0)
  449.     TV, BYTSCL(originalImage, TOP=top, MAX=maxa, MIN=mina)
  450.  
  451.     ;  Draw a circle.
  452.     ;
  453.     x = FINDGEN(60) * (!pi * 2 / 59) 
  454.     na2 = imageSize/2.
  455.     PLOTS, na2 * COS(x) +na2, na2*SIN(x) +na2, /DEVICE, COLOR=top+1
  456.     comp_view = 0
  457.  
  458.     ;  Sort indices by i,j, where k = nangles * j / 2^i
  459.     ;
  460.     ind = INDGEN(nangles)   ;Indices of projections
  461.     if (0) then begin
  462.         j=1
  463.         mm = CEIL(ALOG(nangles) / ALOG(2.0))
  464.  
  465.         for k=1, mm do for i=1,2L^k-1,2 do begin
  466.             kk = i*2L^mm/2L^k
  467.             if (kk LT nangles) then begin
  468.                 ind(j) = kk
  469.                 j = j+1
  470.             endif
  471.         endfor
  472.     endif
  473.  
  474.     ;  Compute the filter function.
  475.     ;
  476.     x = FINDGEN(2*kernelSize+1)-kernelSize
  477.     ker = call_function(filters(filter), x, 1.0)         ; Point spacing is 1.0
  478.     ker = ker / (TOTAL(ker) * nangles * SQRT(imageSize)) ; Normalize it
  479.  
  480.     np = FIX(SQRT(2.) * imageSize/pointSpacing + kernelSize + 4)
  481.     sinogramImage = FLTARR(np, nangles)
  482.     convolvedSinogramImage = FLTARR(np, nangles)
  483.     t0 = 0.
  484.     shiftValue = -(np-imageSize)/2
  485.     WIDGET_CONTROL, labels(3), SET_VALUE='Convolved Sinogram      '
  486.     chunk = nangles/32 > 1
  487.     first = 1
  488.  
  489.     ;  Draw the image section for every angle.
  490.     ;
  491.     for i=0,nangles-1 do begin
  492.         WSET, window(0)
  493.         DEVICE, SET_GRAPH=6
  494.  
  495.         ;  Erase the old line.
  496.         ;
  497.         if (i NE 0) then $   
  498.                 PLOTS, [na2+x, na2-x], [na2+y, na2-y], /DEVICE, COLOR=top/2
  499.  
  500.         t = i * !pi / nangles
  501.         t1 = SYSTIME(1)
  502.         x = SIN(t) * na2
  503.         y = COS(t) * na2
  504.  
  505.         ;  Draw the line except for last one.
  506.         ;
  507.         if (i NE (nangles-1)) then $ 
  508.             PLOTS, [na2+x, na2-x], [na2+y, na2-y], /DEVICE, COLOR=top/2
  509.  
  510.         ;  Compute the various images.
  511.         ;
  512.         device, SET_GRAPH=3
  513.         p = FLTARR(np)
  514.         riemann, p, originalImage, t, BILINEAR=interp EQ 1, $
  515.             CUBIC=interp EQ 2, D=pointSpacing
  516.         sinogramImage(0,i) = p
  517.         convolvedSinogramImage(0,i) = CONVOL(p, ker)
  518.         t0 = t0 + SYSTIME(1) - t1
  519.  
  520.         if ((i LT imageSize) AND ((i mod chunk) EQ (chunk-1)) ) then begin
  521.             WSET, window(2)
  522.             if (first) then erase
  523.             i0 = i - chunk+1
  524.             TV, BYTSCL(shift(sinogramImage(*,i0:i), shiftValue), TOP=top), 0, i0
  525.             WSET, window(3)
  526.             if (first) then erase
  527.             first = 0
  528.             TV, BYTSCL(SHIFT(convolvedSinogramImage(*,i0:i), shiftValue), $
  529.                 TOP=top), 0, i0
  530.         endif
  531.  
  532.         str = "View "+STRTRIM(i,2)
  533.         sText.text[6] = str
  534.         textChange = ['views','void1']
  535.         putTips, sText, wText[1], $
  536.             textChange, [1,2]
  537.  
  538.     endfor
  539.  
  540.     str = 'execution time : ' + string(t0, FORMAT='(f7.2)') + ' sec.'
  541.     sText.text[7] = str
  542.     textChange = ['xtime']
  543.     putTips, sText, wText[1], $
  544.             textChange, [2]
  545.  
  546.     ;  Display the sinogram.
  547.     ;
  548.     WSET, window(2)
  549.     sinogramImage = BYTSCL((SHIFT(sinogramImage, $
  550.         shiftVAlue))(0:imageSize-1,*), TOP=top)
  551.     zoomFactor = 1                  ;Zoom factor
  552.     TV, sinogramImage
  553.  
  554.     ;  Draw the convolved sinogram image.
  555.     ;
  556.     WSET, window(3)
  557.     TV, BYTSCL(shift(convolvedSinogramImage, shiftValue), TOP=top)
  558.  
  559.     ;  Compute and draw the reconstructed image.
  560.     ;
  561.     reconImage = FLTARR(imageSize, imageSize)
  562.  
  563.     step = 1 > (nangles/32)
  564.     t0 = 0.
  565.  
  566.     WSET, window(1)
  567.     erase
  568.     for i=0,nangles-1 do begin
  569.         j = ind(i)
  570.         t = j * !pi / nangles   ;The angle
  571.         t1 = SYSTIME(1)
  572.  
  573.         riemann, convolvedSinogramImage(*,j), $
  574.             reconImage, t, /BACK, D=pointSpacing, $
  575.             BILINEAR=interp EQ 1, CUBIC=interp EQ 2
  576.  
  577.         t0 = t0 + SYSTIME(1)-t1
  578.         if (i MOD step EQ 0) then begin
  579.  
  580.             if 0 then begin             ;NO OPPED
  581.                 WSET, window(0)
  582.                 DEVICE, SET_GRAPH=6
  583.                 if i ne 0 then $
  584.                     PLOTS, [na2+x, na2-x], [na2+y, na2-y], /DEVICE, COLOR=top/2
  585.                 x = -SIN(t) * na2
  586.                 y = COS(t) * na2
  587.                 if i ne (nangles-1) then $          ;Erase old
  588.                     PLOTS, [na2+x, na2-x], [na2+y, na2-y], /DEVICE, COLOR=top/2
  589.                 DEVICE, SET_GRAPH=3
  590.                 WSET, window(1)
  591.             endif                       ;NO OPPED
  592.  
  593.             TV, BYTSCL(reconImage, TOP=top)
  594.         endif
  595.  
  596.         str = "View "+STRTRIM(i,2)
  597.         sText.text[6] = str
  598.         textChange = ['views']
  599.         putTips, sText, wText[1], $
  600.             textChange, [1]
  601.  
  602.     endfor
  603.  
  604.     scaledReconImage =  BYTSCL(reconImage, TOP=top)
  605.     tv, scaledReconImage
  606.  
  607.     meana = TOTAL(originalImage)/N_ELEMENTS(originalImage)
  608.     meanb = TOTAL(reconImage)/N_ELEMENTS(reconImage)
  609.     ss = SQRT(TOTAL((originalImage-meana)^2) / TOTAL((reconImage-meanb)^2))
  610.     reconImage = (reconImage-meanb) * ss + meana
  611.     errorImage = abs(originalImage-reconImage)
  612.     errtot = LONG(TOTAL(errorImage^2))
  613.  
  614.     str1 = 'execution time : ' + string(t0, FORMAT='(f7.2)') + ' sec.'
  615.     str2 = "error norm : "+ string(errtot, FORMAT="(i8)")
  616.     sText.text[7] = str1
  617.     sText.text[8] = str2
  618.     textChange = ['error','xtime']
  619.     putTips, sText, wText[1], $
  620.         textChange, [1,2]
  621.  
  622.     ;  Draw the error image.
  623.     ;
  624.     WSET, window(3)
  625.     WIDGET_CONTROL, labels(3), $
  626.         SET_VALUE='Error (Click window)'
  627.     TV, BYTSCL(errorImage, MAX=maxa, MIN=0, TOP=top)
  628.  
  629.     if (nimages EQ 0) then begin      ;Save history
  630.         pimage = BYTARR(imageSize, imageSize, 4, /NOZERO)
  631.         pimagestr = STRARR(4)
  632.     endif
  633.  
  634.     pimage(0, 0, nimages MOD 4) = scaledReconImage
  635.     pimagestr(nimages MOD 4) = STRING(filters(filter), STRTRIM(nangles,2), $
  636.         ([ 'NN', 'In','Cu'])(interp), STRTRIM(kernelSize*2+1,2), STRTRIM(errtot,2),$
  637.         FORMAT="(a4, ',V',a, ',',a, ',K',a,',E',a)")
  638.     nimages = nimages+1
  639.  
  640.     ;  Resensitze the bases when reconstruction is done.
  641.     ;
  642.     WIDGET_CONTROL, Bar_base, SENSITIVE=1
  643.     WIDGET_CONTROL, wSubBase, SENSITIVE=1
  644.  
  645. end    ;  reconstruct_it
  646.  
  647.  
  648. ;--------------------------------------------------------------------
  649. ;
  650. ;    PURPOSE  Redraw the phanton, sinogram, etc.
  651. ;
  652. pro Recon_Redraw, $
  653.     force     ; IN: flag indicator      
  654.  
  655.     common tomodemo_com
  656.  
  657.     ;  Do nothing (return) under certain conditions.
  658.     ;
  659.     if ( (NOT comp_view) AND (force eq 0)) then RETURN
  660.  
  661.     ;  Reset the original window titles.
  662.     ;
  663.     for  i= 0,3 do WIDGET_CONTROL, labels(i), SET_VALUE=lnames(i)
  664.  
  665.     WSET, window(0)
  666.     TV, BYTSCL(originalImage, TOP=top, MIN=mina, MAX=maxa)
  667.  
  668.     if (ReconstructFlag EQ 0) then begin
  669.         WSET, window(2)
  670.         erase
  671.         WSET, window(1)
  672.         erase
  673.         WSET, window(3)
  674.         erase
  675.     endif
  676.  
  677.     if (N_ELEMENTS(sinogramImage) GT 1) then begin
  678.         WSET, window(2)
  679.         erase
  680.  
  681.         if (force EQ 1) then begin
  682.             TV, REBIN(sinogramImage, imageSize, zoomFactor*nangles)
  683.         endif
  684.  
  685.         WSET, window(1)
  686.         erase
  687.  
  688.         if (force EQ 1) then begin
  689.             TV, BYTSCL(reconImage, TOP=top)
  690.         endif
  691.  
  692.         WSET, window(3)
  693.         erase
  694.  
  695.         if (force EQ 1) then begin
  696.             TV, BYTSCL(ABS(originalImage-reconImage), MAX=maxa, MIN=0, TOP=top)
  697.         endif
  698.     endif
  699.  
  700.     textChange = ['error','xtime']
  701.     putTips, sText, wText[1], $
  702.         textChange, [1,2]
  703.  
  704.     comp_view = 0
  705. end   ;  of  recon_redraw
  706.  
  707. ;--------------------------------------------------------------------
  708. ;
  709. ;    PURPOSE  Main event handler
  710. ;
  711. pro Rec_Demo_Event, $
  712.     sEvent        ; IN: event structure    
  713.  
  714.     common tomodemo_com
  715.  
  716.     ;  Quit the application using the close box.
  717.     ;
  718.     if (TAG_NAMES(sEvent, /STRUCTURE_NAME) EQ $
  719.         'WIDGET_KILL_REQUEST') then begin
  720.         WIDGET_CONTROL, sEvent.top, /DESTROY
  721.         RETURN
  722.     endif
  723.  
  724.     forward_function DemoMenuChoice
  725.  
  726.     WIDGET_CONTROL, sEvent.top, /HOURGLASS
  727.  
  728.     ;  Branch accordingly to the event ID
  729.     ;  (which widget created that event)
  730.     ;
  731.     case sEvent.id of
  732.  
  733.         ;  Reconstruct the image.
  734.         ;
  735.         wReconstructButton: goto, do_reconstruction
  736.  
  737.         ;  Button press within the original view area.
  738.         ;  Draw the cursor location with a small square on the original
  739.         ;  image and draw the corresponding curve on the sinogram.
  740.         ;
  741.         draw(0): begin       
  742.  
  743.             ;  Return if the button  was not the left mouse button or
  744.             ;  the composite view does not exist or the
  745.             ;  sinogram image does not exist.
  746.             ;
  747.             if ((sEvent.press NE 0) OR comp_view) then RETURN
  748.             if (N_ELEMENTS(sinogramImage) LE 1) then RETURN
  749.  
  750.             ocolors(0) = (ocolors(0)+1) mod 4
  751.             c = ocolors(0) + top + 1
  752.             WSET, window(0)
  753.             PLOTS, sEvent.x, sEvent.y, COLOR=c, /DEVICE, PSYM=6
  754.             x = (sEvent.x - imageSize/2)
  755.             y = (sEvent.y - imageSize/2)
  756.             t = FINDGEN(nangles+1)* (!pi / nangles) ;Rotate by theta
  757.             t = (COS(t) * x + SIN(t) * y) + (imageSize/2)
  758.  
  759.             ;  Draw the line on the sinogram image.
  760.             ;
  761.             WSET, window(2)
  762.             i = (imageSize /(2* nangles)) > 1
  763.  
  764.             if (i NE zoomFactor) and (N_ELEMENTS(sinogramImage) GT 1) then begin
  765.                 zoomFactor = i
  766.                 TV, REBIN(sinogramImage, imageSize, zoomFactor * nangles)
  767.             endif
  768.  
  769.             PLOTS, t, zoomFactor*FINDGEN(nangles), COLOR=c, /DEVICE
  770.  
  771.             empty
  772.  
  773.         endcase   ;  of draw(0)
  774.  
  775.         ;  Show the error on the horizontal line where the
  776.         ;  left mouse button was pressed on the error view.
  777.         ;  Open an error view window if it does not already exist.
  778.         ;
  779.         draw(3): begin            
  780.  
  781.             ;  Return if the button  was not the left mouse button or
  782.             ;  the composite view does not exist or the
  783.             ;  reconstructed image does not exist or the
  784.             ;  error or sinogram images do not exist.
  785.             ;
  786.             if ((sEvent.press Ne 0) OR comp_view) then RETURN
  787.             if (N_ELEMENTS(reconImage) LE 1) then RETURN
  788.             if (N_ELEMENTS(sinogramImage) LE 1) then RETURN
  789.         
  790.             charscale = 8.0/!d.X_CH_SIZE
  791.         
  792.             ;  Check if the error plot already exist, if so return
  793.             ;
  794.             errorStatus = WIDGET_INFO(drawErrorID, /VALID_ID)
  795.             if (errorStatus EQ 0) then begin
  796.             
  797.                 ;  Create a new window that displays the error plot.
  798.                 ;
  799.                 errorBase = WIDGET_BASE(TLB_FRAME_ATTR=1, $
  800.                     TITLE ='Error', $
  801.                     XOFFSET=75, YOFFSET=75, $
  802.                     GROUP_LEADER=base)
  803.  
  804.                     drawErrorID = WIDGET_DRAW(errorBase, $
  805.                         SCR_XSIZE=250, SCR_YSIZE=250)
  806.             
  807.                 WIDGET_CONTROL, errorBase, /REALIZE
  808.             endif
  809.         
  810.             WIDGET_CONTROL, drawErrorID, GET_VALUE=errorWindow
  811.  
  812.             WSET, errorWindow
  813.             y = sEvent.y
  814.             PLOT, originalImage(*,y), YRANGE=[mina, maxa], XSTYLE=3, YSTYLE=2, $
  815.                 TITLE='Row '+STRTRIM(y,2), XMARGIN=[4,1], YMARGIN=[2,2], $
  816.                 CHARSIZE = 1.0*charscale
  817.  
  818.             OPLOT, reconImage(*,y), COLOR=top+2, PSYM=3
  819.  
  820.             empty
  821.  
  822.         endcase   ;  of draw(3)
  823.  
  824.         ;  When the left mouse button is pressed within the
  825.         ;  sinogram view area, draw a small square to mark the
  826.         ;  cursor location and draw the corresponding curve on the
  827.         ;  original image.
  828.         ;
  829.         draw(2): begin   
  830.  
  831.             ;  Return if the button  was not the left mouse button or
  832.             ;  the composite view does not exist or the
  833.             ;  sinogram image does not exist.
  834.             ;
  835.             if ((sEvent.press NE 0) OR comp_view) then RETURN
  836.             if N_ELEMENTS(sinogramImage) le 1 then return
  837.             if N_ELEMENTS(zoomFactor) le 0 then zoomFactor = 1 ;Within image?
  838.  
  839.             if (sEvent.y GE nangles*zoomFactor) then RETURN
  840.  
  841.             ocolors(2) = (ocolors(2) + 1) mod 4
  842.             c = ocolors(2) + top + 1
  843.             na2 = imageSize/2
  844.             WSET, window(2)
  845.             PLOTS, sEvent.x, sEvent.y, COLOR=c, /DEVICE, PSYM=6
  846.  
  847.             s = sEvent.x - na2                 ;  Radial distance
  848.             t = sEvent.y/zoomFactor * !pi / nangles    ;  Angle in radians
  849.  
  850.             ;  Display the angle and the x distance from center
  851.             ;  informations.
  852.             ;
  853.             str1 = 'Theta :' + string(t*180./!pi, FORMAT="(f5.1)")
  854.             str2 = 'X from center :' + string(s, FORMAT="(f6.1)")
  855.             sText.text[10] = str1
  856.             sText.text[11] = str2
  857.             textChange = ['theta', 'cente']
  858.             putTips, sText, wText[1], $
  859.                 textChange, [1,2]
  860.  
  861.             x = [-na2, 0, na2]
  862.             st = SIN(t)
  863.             ct = COS(t)
  864.  
  865.             if (t NE 0.0) then begin
  866.                 y = (s - x * ct) / st + na2
  867.             endif else begin
  868.                 y=[0, imageSize-1]
  869.                 x = [sEvent.x, sEvent.x]-na2
  870.             endelse
  871.  
  872.             ;  Draw the corresponding curve on the original image.
  873.             ;
  874.             WSET, window(0)
  875.             PLOTS, x+na2, y, /DEVICE, COLOR=c     ;Show projection
  876.             py = sinogramImage(*, sEvent.y/zoomFactor) ;Draw the profile, rotated....
  877.             py = py * (imageSize/(5.*max(py)))
  878.             px = FINDGEN(imageSize) - na2
  879.             PLOTS, ct * px - st * py + na2, $
  880.                 st * px + ct * py + na2  , /DEVICE, COLOR=c
  881.             empty
  882.         endcase   ;  of draw(2)
  883.  
  884.         ;  Do nothing (return) when the mouse button is pressed
  885.         ;  on the reconstructed image.
  886.         ;
  887.         draw(1): RETURN 
  888.  
  889.         ;  Set the number of angles.
  890.         ;
  891.         wAngleButton:   nangles = 2^(sEvent.index+2)
  892.  
  893.         ;  Set the type of filter.
  894.         ;
  895.         wFilterButton:  filter = sEvent.index
  896.  
  897.         ;  Set the kernel size.
  898.         ;
  899.         wKernelButton:  kernelSize = 2^sEvent.index
  900.  
  901.         ;  Set the interpolation method.
  902.         ;
  903.         wInterpButton:  interp = sEvent.index
  904.  
  905.         ;  Any other event must be a menu button.
  906.         ;
  907.         else: begin    
  908.  
  909.             ;  Get the user value of the button.
  910.             ;
  911.             WIDGET_CONTROL, sEvent.id, GET_UVALUE=uv
  912.  
  913.             uv1 = STR_SEP(uv, "|")
  914.  
  915.             ;  Branch to the appropriate button event.
  916.             ;
  917.             case uv1(1) of
  918.                 'File': case uv1(2) of
  919.  
  920.                     ;  Quit this application.
  921.                     ;
  922.                     'Quit': begin
  923.                         originalImage = 0       ;Remove images & clean up.
  924.                         reconImage=0
  925.                         sinogramImage = 0
  926.                         pimage=0
  927.                         pimagestr=0
  928.                         WIDGET_CONTROL, sEvent.top, /DESTROY
  929.                         RETURN
  930.                     endcase
  931.  
  932.                     ;  Draw the newly selected object and destroy the
  933.                     ;  previous one and its associated images.
  934.                     ;
  935.                     'Object': begin
  936.                         WSET, window(0)
  937.                         object = DemoMenuChoice(uv, MenuItems, MenuButtons) + 1
  938.                         originalImage = make_phantom(imageSize, object)
  939.                         maxa = max(originalImage, MIN=mina)
  940.                         sinogramImage = 0
  941.                         ReconstructFlag = 0
  942.                         recon_redraw, 1
  943.  
  944.                         ;  Destroy the error window.
  945.                         ;
  946.                         if ( widget_info(errorbase, /VALID_ID)) then begin
  947.                             WIDGET_CONTROL, errorBase, /DESTROY
  948.                         endif
  949.                         nimages = 0
  950.  
  951.                         ;  Set the execution time, error norm, theta, and
  952.                         ;  center text fields to nothing.
  953.                         ;
  954.                         sText.text[7] = ' '
  955.                         sText.text[8] = ' '
  956.                         sText.text[10] = ' '
  957.                         sText.text[11] = ' '
  958.  
  959.                         ;  Reset the tips text.
  960.                         ;
  961.                         textChange = ['click', 'numer']
  962.                         putTips, sText, wText[1], $
  963.                             textChange, [1,2]
  964.  
  965.                     endcase
  966.  
  967.                     'Reconstruct': begin
  968.                         do_reconstruction:
  969.                         WIDGET_CONTROL, base, /HOURGLASS
  970.                         reconstruct_it
  971.                         ReconstructFlag = 1
  972.  
  973.                         ;  Destroy the error window.
  974.                         ;
  975.                         if ( widget_info(errorbase, /VALID_ID)) then begin
  976.                             WIDGET_CONTROL, errorBase, /DESTROY
  977.                         endif
  978.                     endcase
  979.  
  980.                 endcase   ;  of uv1(2)  or File
  981.  
  982.                 ;  Display the information text file.
  983.                 ;
  984.                 'About': begin     
  985.                     if (Xregistered('Xdisplayfile') NE 0) then RETURN
  986.  
  987.                     Xdisplayfile, filepath("reconstr.txt", $
  988.                         SUBDIR=['examples','demo','demotext']), $
  989.                         TITLE="About the Reconstruction Demo", $
  990.                         GROUP=sEvent.top, DONE_BUTTON='Done', $
  991.                         WIDTH=55, HEIGHT=14
  992.                 endcase
  993.  
  994.                 ;  Load a new color table.
  995.                 ;
  996.                 'Edit': begin      
  997.                     if (Xregistered('XLoadct') NE 0) then  RETURN
  998.                     XLOADCT, NCOLORS=top, GROUP=sEvent.top
  999.                 endcase
  1000.  
  1001.    
  1002.                 'View': case uv1(2) of
  1003.  
  1004.                     ;  Redraw all the views. 
  1005.                     ;
  1006.                     'Redraw': begin
  1007.                         recon_redraw, 1
  1008.                     endcase
  1009.  
  1010.                     ;  Compare the previous reconstructed image with the 
  1011.                     ;  current one for the same object.
  1012.                     ;
  1013.                     'Compare': begin
  1014.                         if (nimages le 1) then return
  1015.                         n = nimages < 4
  1016.                         for i=nimages-n, nimages-1 do begin
  1017.                             j = i - nimages+n
  1018.                             WSET, window(j)
  1019.                             WIDGET_CONTROL, labels(j), SET_VALUE=pimagestr(i mod 4)
  1020.                             TV, pimage(*,*,i mod 4)
  1021.                         endfor
  1022.                         comp_view = 1
  1023.                     endcase
  1024.  
  1025.                 endcase             ; of  View
  1026.  
  1027.             endcase     ;  of uv1 (menu bar buttons)
  1028.  
  1029.         endcase         ;  of else
  1030.  
  1031.     endcase             ;  of sEvent.id
  1032.  
  1033. end                     ;  of event handler
  1034.  
  1035.  
  1036. ;--------------------------------------------------------------------
  1037. ;
  1038. ;    PURPOSE  Cleanup procedure.
  1039. ;
  1040. pro Reconstr_Cleanup, $
  1041.     tlb     ;  IN: top level base identifier
  1042.  
  1043.     ;  Get the color table saved in the window's user value.
  1044.     ;
  1045.     WIDGET_CONTROL, tlb, GET_UVALUE=info, /NO_COPY
  1046.  
  1047.     ;  Restore the previous color table.
  1048.     ;
  1049.     TVLCT, info.colorTable
  1050.  
  1051.     ;  Map the group leader base if it exists.
  1052.     ;
  1053.     if (WIDGET_INFO(info.groupBase, /VALID_ID)) then $
  1054.         WIDGET_CONTROL, info.groupBase, /MAP
  1055.  
  1056. end              ; Of Reconstr_Cleanup
  1057.  
  1058. ;--------------------------------------------------------------------
  1059. ;
  1060. ;    PURPOSE  Cleanup procedure.
  1061. ;
  1062. pro D_Reconstr, $
  1063.     ImageSizeIn,  $      ; IN: (opt) image size vector
  1064.     GROUP=group, $     ; IN: (opt) group identifier
  1065.     APPTLB = appTLB    ; OUT: (opt) TLB of this application
  1066.  
  1067.     common tomodemo_com
  1068.  
  1069.     ; Check the validity of the group identifier.
  1070.     ;
  1071.     ngroup = N_ELEMENTS(group)
  1072.     if (ngroup NE 0) then begin
  1073.         check = WIDGET_INFO(group, /VALID_ID)
  1074.         if (check NE 1) then begin
  1075.             print,'Error, the group identifier is not valid'
  1076.             print, 'Return to the main application'
  1077.             RETURN
  1078.         endif
  1079.         groupBase = group
  1080.     endif else groupBase = 0L
  1081.  
  1082.     ;  Save the current color table.
  1083.     ;
  1084.     TVLCT, savedR, savedG, savedB, /GET
  1085.     colorTable = [[savedR], [savedG], [savedB]]
  1086.  
  1087.     ;  Initialize sizes.
  1088.     ;
  1089.     if (N_ELEMENTS(ImageSizeIn) LE 0) then begin
  1090.         DEVICE, GET_SCREEN = x
  1091.         if (x(0) GT 1024) then ImageSize=256 $
  1092.             else if x(0) ge 800 then ImageSize=192 $
  1093.             else ImageSize = 128
  1094.     endif else begin
  1095.         imageSize = imageSizeIn
  1096.     endelse
  1097.  
  1098.     ;  Get the tips.
  1099.     ;
  1100.     sText = getTips(filepath('reconstr.tip', $
  1101.         SUBDIR=['examples','demo', 'demotext']) )
  1102.  
  1103.     ;  Create the starting up message.
  1104.     ;
  1105.     if (ngroup EQ 0) then begin
  1106.         drawbase = startmes()
  1107.     endif else begin
  1108.         drawbase = startmes(GROUP=group)
  1109.     endelse
  1110.  
  1111.  
  1112.     ;  Initialize working parameters and arrays.
  1113.     ;
  1114.     imageSize = ImageSize           ; Default values
  1115.     filter = 2                      ; Shepp Logan
  1116.     interp = 1                      ; Linear
  1117.     nangles = 32
  1118.     kernelSize = 8
  1119.     pointSpacing = 1.               ; Point spacing
  1120.     zoomFactor = 1
  1121.     object = 4
  1122.     n = 2 * imageSize
  1123.     draw = LONARR(4)
  1124.     window = LONARR(4)
  1125.     ocolors = INTARR(4)             ; Overlay colors
  1126.     pimage=0
  1127.     nimages=0
  1128.     comp_view = 0                   ; Showing normal view
  1129.     ReconstructFlag = 0
  1130.  
  1131.     ;  Initialize the filter options, None must be 1st filter....
  1132.     ;
  1133.     filters=  ['None', 'RamLak', 'Shepp_Logan', $
  1134.         'LP_Cosine', 'Gen_Hamming']
  1135.  
  1136.     ;  Initialize the windows labels (names).
  1137.     ;
  1138.     lnames = ['Original                ', $
  1139.               'Reconstruction          ', $
  1140.               'Sinogram                ', $
  1141.               'Error                   ']
  1142.     ;  Create the widgets starttin g with the top level base.
  1143.     ;
  1144.     if (N_ELEMENTS(group) EQ 0) then begin
  1145.         base = WIDGET_BASE(TITLE='Reconstruction Demo', $
  1146.             MAP=0, $
  1147.             /TLB_KILL_REQUEST_EVENTS, $
  1148.             MBAR=bar_base, TLB_FRAME_ATTR=1, /COLUMN)
  1149.     endif else begin
  1150.         base = WIDGET_BASE(TITLE='Reconstruction Demo', $
  1151.             GROUP_LEADER=group, $
  1152.             MAP=0, $
  1153.             /TLB_KILL_REQUEST_EVENTS, $
  1154.             MBAR=bar_base, TLB_FRAME_ATTR=1, /COLUMN)
  1155.     endelse
  1156.  
  1157.         MenuItems = [ $
  1158.             '1File', $
  1159.             '1Object', '0Shepp-Logan Phantom', '0Circles', '0Squares','6CT Slice', $
  1160.             '0Reconstruct', '2Quit', $
  1161.             '1Edit', '2Color Palette', $
  1162.             '1View', '0Redraw', '2Compare', $
  1163.             '1About', '2About Reconstruction' ]
  1164.  
  1165.         ;  Create the menu bar and all its buttons.
  1166.         ;
  1167.         DemoMenuCreate, MenuItems, MenuButtons, Bar_base
  1168.  
  1169.         ;  Create a sub base that has the left and right bases.
  1170.         ;
  1171.         wSubBase = WIDGET_BASE(base, COLUMN=2)
  1172.  
  1173.             ;  Create the base that has options and functionality buttons.
  1174.             ;
  1175.             wLeftBase = WIDGET_BASE(wSubBase, /COLUMN, /BASE_ALIGN_CENTER)
  1176.  
  1177.                 ;  Create the angel base.
  1178.                 ;
  1179.                 wViewBase = WIDGET_BASE(wLeftBase, /COLUMN)
  1180.  
  1181.                     ;  Create the angel base.
  1182.                     ;
  1183.                     wAngleBase = WIDGET_BASE(wViewBase, $
  1184.                         /BASE_ALIGN_LEFT, /COLUMN)
  1185.  
  1186.                         ;  Create the number of angles droplist.
  1187.                         ;
  1188.                         wAnglesLabel = WIDGET_LABEL(wAngleBase, $
  1189.                             VALUE='Number of angles :')
  1190.  
  1191.                         ;  Droplist to select the nuimber of angles.
  1192.                         ;
  1193.                         wAngleButton = WIDGET_DROPLIST(wAngleBase, $
  1194.                             VALUE= ['4','8','16','32','64','128','256'])
  1195.  
  1196.                 ;  Create the filter base.
  1197.                 ;
  1198.                 wFilterBase = WIDGET_BASE(wLeftBase, /COLUMN, /FRAME)
  1199.  
  1200.                     ;  Create the number of angles droplist.
  1201.                     ;
  1202.                     wFilterLabel = WIDGET_LABEL(wFilterBase, $
  1203.                         /ALIGN_CENTER, $
  1204.                         VALUE='Filter')
  1205.  
  1206.                     ;  Create the sub base of filter base.
  1207.                     ;
  1208.                     wSubFilterBase = WIDGET_BASE(wFilterBase, $
  1209.                     /BASE_ALIGN_LEFT,  /COLUMN)
  1210.  
  1211.                         ;  Create the filter type label.
  1212.                         ;
  1213.                         wTypeLabel = WIDGET_LABEL(wSubFilterBase, $
  1214.                             VALUE='Type :')
  1215.  
  1216.                         ;  Droplist to select the filter type.
  1217.                         ;
  1218.                         wFilterButton = WIDGET_DROPLIST(wSubFilterBase, $
  1219.                             VALUE=filters)
  1220.  
  1221.                         ;  Create the kernel size label.
  1222.                         ;
  1223.                         wTypeLabel = WIDGET_LABEL(wSubFilterBase, $
  1224.                             VALUE='Kernel size :')
  1225.  
  1226.                         ;  Droplist to select the kernel size.
  1227.                         ;
  1228.                         wKernelButton = WIDGET_DROPLIST(wSubFilterBase, $
  1229.                             VALUE=['3','5','9','17','33','65'])
  1230.  
  1231.                         ;  Create the interpolation label.
  1232.                         ;
  1233.                         wInterpolationLabel = WIDGET_LABEL(wSubFilterBase, $
  1234.                             VALUE='Interpolation :')
  1235.  
  1236.                         ;  Droplist to select the interpolation method.
  1237.                         ;
  1238.                         wInterpButton = WIDGET_DROPLIST(wSubFilterBase, $
  1239.                             VALUE=['Nearest Neighbor','Linear','Cubic'])
  1240.  
  1241.  
  1242.                 ;  Create the reconstruct button.
  1243.                 ;
  1244.                 wReconstructButton = WIDGET_BUTTON(wLeftBase, $
  1245.                     VALUE='Reconstruct', /NO_RELEASE)
  1246.  
  1247.             ;  Create the base that has options and functionality buttons.
  1248.             ;
  1249.             wRightBase = WIDGET_BASE(wSubBase, /COLUMN)
  1250.  
  1251.                 wRow1Base = WIDGET_BASE(wRightBase, /ROW) ;2 x 2 bases
  1252.                     temp = LONARR(4)
  1253.                     labels = LONARR(4)
  1254.  
  1255.                     for i=0,1 do temp(i) = WIDGET_BASE(wRow1Base, /COLUMN)
  1256.  
  1257.                 wRow2Base = WIDGET_BASE(wRightBase, /ROW)
  1258.  
  1259.                     for i=2,3 do temp(i) = WIDGET_BASE(wRow2Base, /COLUMN)
  1260.  
  1261.                     for i=0,3 do begin
  1262.                         labels(i) = WIDGET_LABEL(temp(i), $
  1263.                             /ALIGN_LEFT, $
  1264.                             /DYNAMIC_RESIZE, $
  1265.                             VALUE=STRING(lnames(i), FORMAT='(a34)'))
  1266.  
  1267.                         draw(i) = WIDGET_DRAW(temp(i), /BUTTON, $
  1268.                             RETAIN=2, $
  1269.                             XSIZE=imageSize, YSIZE=imageSize)
  1270.                     endfor
  1271.  
  1272.                     for i=0,3 do WIDGET_CONTROL, labels(i), SET_VALUE=lnames(i)
  1273.  
  1274.         ;  Create the status line label.
  1275.         ;
  1276.         wStatusBase = WIDGET_BASE(base, MAP=0, /ROW)
  1277.  
  1278.             nWidgets = 2
  1279.             wText = LONARR(nWidgets)
  1280.             widTips, wStatusBase, sText.text, XSIZE=36, $
  1281.                 YSIZE=3, NWIDGETS=nWidgets, wText
  1282.  
  1283.  
  1284.  
  1285.     ;  Realize the widget hierarchy.
  1286.     ;
  1287.     WIDGET_CONTROL, base, /REALIZE
  1288.  
  1289.     WIDGET_CONTROL, wAngleButton, SET_DROPLIST_SELECT=3
  1290.     WIDGET_CONTROL, wFilterButton, SET_DROPLIST_SELECT=filter
  1291.     WIDGET_CONTROL, wKernelButton, SET_DROPLIST_SELECT=3
  1292.     WIDGET_CONTROL, wInterpButton, SET_DROPLIST_SELECT=1
  1293.  
  1294.     ;  Make the angle and filter base the same x dimension.
  1295.     ;
  1296.     szAngle = WIDGET_INFO(wAngleBase, /GEOMETRY)
  1297.     szFilter = WIDGET_INFO(wSubFilterBase, /GEOMETRY)
  1298.     xAngle = szAngle.scr_xsize + ( 2* szAngle.margin)
  1299.     xFilter = szFilter.scr_xsize + ( 2* szFilter.margin)
  1300.     if (xAngle LT xFilter) then begin
  1301.         WIDGET_CONTROL, wAngleBase, SCR_XSIZE=xFilter
  1302.     endif else begin
  1303.         WIDGET_CONTROL, wFilterBase, SCR_XSIZE=xAngle
  1304.     endelse
  1305.  
  1306.     ; Returns the top level base to the APPTLB keyword.
  1307.     ;
  1308.     appTLB = base
  1309.  
  1310.     ;  Size the tips widgets.
  1311.     ;
  1312.     sizeTips, base, wText, wStatusBase
  1313.  
  1314.     ;  Get the windows (drawing areas) identifiers.
  1315.     ;
  1316.     for i=0,3 do begin
  1317.         WIDGET_CONTROL, draw(i), GET_VALUE=j
  1318.         window(i) = j
  1319.     endfor
  1320.     top = !D.TABLE_SIZE-6
  1321.  
  1322.     ;  Load the grey scale colr table.
  1323.     ;
  1324.     LOADCT, 0, /SILENT, NCOLORS=top+1
  1325.  
  1326.     ;  Allocate working colors : red, green, yellow, blue, white.
  1327.     ;
  1328.     TVLCT, [255,0,255,0,255],[0,255,255,0,255],[0,0,0,255,255], top+1
  1329.  
  1330.     ;  Destroy the starting up window.
  1331.     ;
  1332.     WIDGET_CONTROL, drawbase, /DESTROY
  1333.  
  1334.     ;  Map the top level base.
  1335.     ;
  1336.     WIDGET_CONTROL, base, MAP=1
  1337.  
  1338.     ;  Load the CT scan image as default.
  1339.     ;
  1340.     originalImage = make_phantom(imageSize, object)   
  1341.     maxa = max(originalImage, MIN=mina)
  1342.     WSET, window(0)
  1343.     TV, BYTSCL(originalImage, TOP=top, MAX=maxa, MIN=mina)
  1344.  
  1345.     ;  Assign an initial value to drawErrorID.
  1346.     ;
  1347.     drawErrorID = -1L
  1348.     errorBase = -1L
  1349.  
  1350.     ;  Create the info structure.
  1351.     ;
  1352.     info = { $
  1353.         ColorTable: colorTable, $
  1354.         groupBase: groupBase $                        ; Base of Group Leader
  1355.     }
  1356.  
  1357.     ;  Assign the info structure into the user value of the top level base.
  1358.     ;
  1359.     WIDGET_CONTROL, base, SET_UVALUE=info, /NO_COPY
  1360.  
  1361.     XMANAGER, 'd_reconstr', base, CLEANUP='Reconstr_Cleanup',  $
  1362.         Event_Handler='rec_demo_event', /NO_BLOCK
  1363. end
  1364.